home *** CD-ROM | disk | FTP | other *** search
/ Dr. Windows 3 / dr win3.zip / dr win3 / VISUALBA / BOZOL2.ZIP / PREP.BAS < prev    next >
BASIC Source File  |  1994-02-08  |  6KB  |  136 lines

  1. SUB PREP (Prg$)
  2. ' Prep can do a lot of things depending on how complicated you want your
  3. ' language to be.  EXEC simply parses the line apart and looks for three
  4. ' things which it can handle.  It looks for statements (PRINT, INPUT), it
  5. ' looks for functions (UCASE, VAL) and it looks for arguments (numbers or
  6. ' variables like A,B,GRANNY,USERNAME).  If this is all we need for our
  7. ' language then PREP is not necessary, PREP is required to do at least 2
  8. ' very necessary things in order to make our language truly viable.  First,
  9. ' EXEC "parses" what is passed to it by looking for spaces, commas and
  10. ' semicolons (these are interchangeable).  EXEC does not understand the
  11. ' concept of QUOTED STRINGS since quoted strings may contain spaces and
  12. ' punctuation that would confuse the parsing technique.  Of course, we
  13. ' could teach EXEC to look for begin and end quotes and not parse or
  14. ' attempt to interpret what is between them, and to simply push the
  15. ' entire quoted string onto the argument stack, but this would really
  16. ' slow things down.  It is better to deal with quoted strings all at once
  17. ' beforehand.  Of course, it would be even better to PREP the WHOLE PROGRAM
  18. ' before it is executed, and this would give us an added opportunity to
  19. ' strip REMarks, pre-establish the positions of labels, and pack out blank
  20. ' lines, but this would start to make this source code harder and harder
  21. ' to understand, and we're trying to make this as easy as we can.
  22.  
  23. ' Remove all quoted strings and make temporary variables out of them.
  24. X%=65
  25. DO
  26. a%=INSTR(PRG$,CHR$(34))
  27. IF a% THEN
  28.         VALUE$=MID$(PRG$, a%)
  29.         b%=INSTR(2,VALUE$,CHR$(34))
  30.         IF b% THEN VALUE$=LEFT$(VALUE$,b%)
  31.         REPLACE VALUE$ WITH CHR$(1,X%) IN PRG$
  32.         ARRAY SCAN VAR$(1), COLLATE UCASE, =CHR$(1,X%), TO i%
  33.         IF i% THEN
  34.             VALUE$(i%)=REMOVE$(VALUE$,CHR$(34))
  35.     ELSE
  36.             INCR NextVar%
  37.                 VALUE$(NextVar%)=REMOVE$(VALUE$,CHR$(34))
  38.                 VAR$(NextVar%)=CHR$(1,X%)
  39.         END IF
  40. ELSE
  41.     EXIT LOOP
  42. END IF
  43. INCR X%
  44. LOOP
  45.  
  46. ' Secondly, we have to deal with the harsh realities of NUMERIC EXPRESSIONS.
  47. ' We could certainly work that into EXEC as well, using a technique called
  48. ' RECURSIVE DESCENT PARSING, but that, too would start making things a bit
  49. ' hideous.
  50. ' Being able to handle an line like ...
  51. '                      PRINT B*20/C+(INT(D/100))
  52. ' ... where a statement is followed by an expression which includes
  53. ' literal numbers and variables and functions (like INT) would require a
  54. ' much more complex parsing algorithm than we are introducing here.
  55. ' Another way to deal with expressions is to force any arithmetic to
  56. ' be performed in special arithmetic functions, like ...
  57. '
  58. '    PRINT ADD(DIV(MUL(B,20),C),INT(DIV(D,100))
  59. '
  60. ' with the stack-parsing technique we are using for language processing
  61. ' this type of expression would be much much much easier to implement, BUT
  62. ' it starts to make our language seem pretty silly, so what we are going to
  63. ' do is this:  By pushing arithmetic symbols onto the argument stack along
  64. ' with the rest of the arguments, a variable-free, statement-free expression
  65. ' can be built whenever the stack is popped clean by the CALC function.
  66. ' in other words, the above expression would wind up looking like this:
  67. '
  68. '     PRINT CALC B*20/C+(INT(CALC D/100))
  69. '
  70. ' ... which I would consider more of a fair compromise, and for the burden
  71. ' of forcing you to use the CALC command before every arithmetic expression
  72. ' you can still use natural arithmetic without having to make your language
  73. ' look like FrameWork Fred. (ick!)  To accomplish this, we have to make
  74. ' sure that arithmetic symbols get parsed and pushed as individuals.  In
  75. ' order for that to happen, we must ensure that they are separated by a
  76. ' parsing character, such as a SPACE.
  77.  
  78. REPLACE "+" WITH " + " IN PRG$
  79. REPLACE "-" WITH " - " IN PRG$
  80. REPLACE "*" WITH " * " IN PRG$
  81. REPLACE "\" WITH " \ " IN PRG$
  82. REPLACE "/" WITH " / " IN PRG$
  83. REPLACE "^" WITH " ^ " IN PRG$
  84. REPLACE "<" WITH " < " IN PRG$
  85. REPLACE ">" WITH " > " IN PRG$
  86. REPLACE "(" WITH " ( " IN PRG$
  87. REPLACE ")" WITH " ) " IN PRG$
  88. REPLACE "=" WITH " = " IN PRG$
  89.  
  90. ' Now, finally, we will be dealing in a free-form program structure where
  91. ' the single string being processed here may contain carriage returns and
  92. ' line feeds.  In the case of multiple lines, we don't want the whole
  93. ' module executed in reverse (which is what stack-parsing does) so we will
  94. ' remove all carriage returns and line feeds, and we'll be flipping the
  95. ' lines, so the last lines come first and the first come last.  To fully
  96. ' understand why we are doing this, you must fully understand stack-parsing.
  97. ' In stack parsing, we push every item in a single statement onto a stack,
  98. ' processing it as it goes, from last to first.  If you have a line which
  99. ' read like this:
  100. '
  101. '               print      mid$      (A$,     Y%,      1)
  102. '               ^^^^^      ^^^^      ^^^^     ^^^      ^^
  103. '        STATEMENT  FUNCTION  VARIABLE VARIABLE ARGUMENT
  104. ' ... the stack-parser start out by pushing the argument 1 as a literal
  105. ' number.  Then it would evaluate Y% and push it's value as a literal
  106. ' number.  Then it would evaluate A$ and push it's contents as a literal
  107. ' string.  Then it would get to the function MID$.  It would POP the three
  108. ' arguments in order to see what it needs to MID$ with, and then push the
  109. ' result as a literal string.  Finally, PRINT would see that one single
  110. ' item on the stack (the result of MID$) and print it.  For more information
  111. ' about stack parsing, go back 20 lines and read this again until you get it.
  112.  
  113. IF INSTR(PRG$,ANY CHR$(13,58)) THEN
  114.         ' remove all line feeds (PBWrite and other text editors produce them)
  115.         ' Add a closing carriage return, just in case, and then reverse
  116.         ' the order of every line of text.
  117.     PRG$=REVERSE$(REMOVE$(PRG$,CHR$(10)))
  118.         ' and remove blank lines
  119. END IF
  120.  
  121. REPLACE "  " WITH " " IN PRG$   ' elimate double spaces
  122.  
  123. END SUB
  124.  
  125. FUNCTION REVERSE$(X$)
  126. IF X$="" THEN EXIT FUNCTION
  127. IF INSTR(X$,ANY CHR$(13,58)) = 0 THEN
  128.     REVERSE$=X$
  129.         EXIT FUNCTION
  130. ELSE
  131.     Y$=LEFT$(X$,INSTR(X$,ANY CHR$(13,58))-1)
  132.         Z$=MID$(X$,INSTR(X$,ANY CHR$(13,58))+1)
  133.         REVERSE$=REVERSE$(Z$)+" " + Y$
  134. END IF
  135.  
  136. END FUNCTION